package user

import (
	"fmt"
	"strings"
	"sync/atomic"
	"time"

	"github.com/miscgo/sorm/model"
	"github.com/miscgo/sorm/singleton"
	"github.com/miscgo/sorm/util"
	"gorm.io/gorm"
)

var (
	userId     int32 = 1000000
	userIdStep int32 = 10
)

type AccountUser struct {
	Id            int       `gorm:"column:id" json:"id" form:"id"`
	Password      string    `gorm:"column:password" json:"password" form:"password"`
	Last_login    time.Time `gorm:"column:last_login" json:"last_login" form:"last_login"`
	Is_superuser  bool      `gorm:"column:is_superuser" json:"is_superuser" form:"is_superuser"`
	Username      string    `gorm:"column:username" json:"username" form:"username"`
	First_name    string    `gorm:"column:first_name" json:"first_name" form:"first_name"`
	Last_name     string    `gorm:"column:last_name" json:"last_name" form:"last_name"`
	Is_staff      bool      `gorm:"column:is_staff" json:"is_staff" form:"is_staff"`
	Is_active     bool      `gorm:"column:is_active" json:"is_active" form:"is_active"`
	Date_joined   time.Time `gorm:"column:date_joined" json:"date_joined" form:"date_joined"`
	Updated       time.Time `gorm:"column:updated" json:"updated" form:"updated"`
	Mobile        string    `gorm:"column:mobile" json:"mobile" form:"mobile"`
	Email         string    `gorm:"column:email" json:"email" form:"email"`
	Email_active  bool      `gorm:"column:email_active" json:"email_active" form:"email_active"`
	Type          string    `gorm:"column:type" json:"type" form:"type"`
	Channel       int       `gorm:"column:channel" json:"channel" form:"channel"`
	Is_supervisor bool      `gorm:"column:is_supervisor" json:"is_supervisor" form:"is_supervisor"`
	Supervisor_id int       `gorm:"column:supervisor_id" json:"supervisor_id" form:"supervisor_id"`
	Source        int       `gorm:"column:source" json:"source" form:"source"`
	Is_tester     bool      `gorm:"column:is_tester" json:"is_tester" form:"is_tester"`
}

func (AccountUser) TableName() string {
	return "account_user"
}

type PingAccountUser struct {
	Id            int       `gorm:"column:id" json:"id" form:"id"`
	Password      string    `gorm:"column:password" json:"password" form:"password"`
	Last_login    time.Time `gorm:"column:last_login" json:"last_login" form:"last_login"`
	Is_superuser  bool      `gorm:"column:is_superuser" json:"is_superuser" form:"is_superuser"`
	Username      string    `gorm:"column:username" json:"username" form:"username"`
	First_name    string    `gorm:"column:first_name" json:"first_name" form:"first_name"`
	Last_name     string    `gorm:"column:last_name" json:"last_name" form:"last_name"`
	Is_staff      bool      `gorm:"column:is_staff" json:"is_staff" form:"is_staff"`
	Is_active     bool      `gorm:"column:is_active" json:"is_active" form:"is_active"`
	Date_joined   time.Time `gorm:"column:date_joined" json:"date_joined" form:"date_joined"`
	Updated       time.Time `gorm:"column:updated" json:"updated" form:"updated"`
	Mobile        string    `gorm:"column:mobile" json:"mobile" form:"mobile"`
	Email         string    `gorm:"column:email" json:"email" form:"email"`
	Email_active  bool      `gorm:"column:email_active" json:"email_active" form:"email_active"`
	Type          string    `gorm:"column:type" json:"type" form:"type"`
	Channel       int       `gorm:"column:channel" json:"channel" form:"channel"`
	Is_supervisor bool      `gorm:"column:is_supervisor" json:"is_supervisor" form:"is_supervisor"`
	Supervisor_id int       `gorm:"column:supervisor_id" json:"supervisor_id" form:"supervisor_id"`
	Source        int       `gorm:"column:source" json:"source" form:"source"`
	Is_tester     bool      `gorm:"column:is_tester" json:"is_tester" form:"is_tester"`
}

func (PingAccountUser) TableName() string {
	return "ping_account_user"
}

func MigrateUser(db *gorm.DB) map[int]int {
	userMap := make(map[int]int)
	begin := time.Now()
	var userList []AccountUser

	var offset int = 0
	var pagesize int = 1000
	var myUserId int

	for {
		fmt.Printf("begin find: offset: %d  \n", offset)
		db.Limit(pagesize).Offset(offset).Order("date_joined").Find(&userList)

		var newUserList []PingAccountUser
		for _, v := range userList {

			p := PingAccountUser{}
			util.Copy(&v, &p)

			if strings.Contains(v.Username, "admin") {
				myUserId = v.Id
			} else {
				myUserId = getUserId()
			}
			//fmt.Printf("user mapping: %d -> %d \n", p.Id, myUserId)
			userMap[p.Id] = myUserId
			p.Id = myUserId
			newUserList = append(newUserList, p)
			validateUser(&v)
		}
		offset += pagesize

		if len(newUserList) > 0 {
			if err := db.CreateInBatches(newUserList, len(newUserList)).Error; err != nil {
				panic(err)
			}
		}

		if len(userList) < pagesize {
			break
		}
	}
	end := time.Now()
	fmt.Printf(" user cost: %v  \n", end.Sub(begin))

	return userMap
}

func getUserId() int {
	return int(atomic.AddInt32(&userId, userIdStep))
}

func GetUser(id int, db *gorm.DB) *AccountUser {
	u := &AccountUser{}
	if err := db.First(u, id).Error; err != nil {
		panic(fmt.Sprintf("userid： %d 不存在", id))
	}
	return u
}

func validateUser(v *AccountUser) {

	var globalCheck []*model.GlobalTimeCheck
	globalCheck = append(globalCheck, &model.GlobalTimeCheck{v.Date_joined, "date_joined"},
		&model.GlobalTimeCheck{v.Last_login, "last_login"}, &model.GlobalTimeCheck{v.Updated, "updated"})

	for _, gtc := range globalCheck {
		// 全局检查
		b, adjustedDay := singleton.TimeGlobalCheck2(fmt.Sprintf("time: %s,  %d", gtc.Column, v.Id), gtc.CheckedTime)
		if !b {
			singleton.WriteToGeneratesqlFile(fmt.Sprintf("// user 时间全局检查 \n select id, %s from  account_user  where id = %d;", gtc.Column, v.Id))
			singleton.WriteToGeneratesqlFile(fmt.Sprintf("update  account_user set  %s  =  '%s' where id = %d;", gtc.Column, adjustedDay, v.Id))
		}
	}

	// 规则一
	b, newDay := singleton.TimeBigSmall(v.Last_login, v.Date_joined, fmt.Sprintf("date_joined  < last_login  %d", v.Id))
	if !b {
		singleton.WriteToGeneratesqlFile(fmt.Sprintf("// user规则一 \n update account_user set last_login =  '%s' where id = %d;", newDay, v.Id))
	}

	// 规则二
	b, newDay = singleton.TimeBigSmall(v.Updated, v.Date_joined, fmt.Sprintf("date_joined < updated  %d", v.Id))
	if !b {
		singleton.WriteToGeneratesqlFile(fmt.Sprintf("// user规则二 \n update account_user set udpated =  %s' where id = %d;", newDay, v.Id))
	}

}
